/************************************************************************************************************************/
/**	CONFIGURATION																										*/
/************************************************************************************************************************/

/* Server config				*/
/* ---------------------------- */
if SERVER then

	/* Add files for download */
	AddCSLuaFile( "shared.lua" )
	AddCSLuaFile( "swep_configurator.lua" )
	
	/* Config */
	SWEP.AutoSwitchFrom			= false					-- Auto switch from if you pick up a better weapon.
	SWEP.AutoSwitchTo			= false					-- Auto switch to if we pick it up.
	SWEP.Weight					= 5						-- Decides whether we should switch from/to this.
	
end

/* Client config				*/
/* ---------------------------- */
if CLIENT then

	include( "swep_configurator.lua" )

	SWEP.BobScale				= 1.0					-- The scale of the viewmodel bob (1.0 should be the default).
	SWEP.BounceWeaponIcon		= false					-- Should the weapon icon bounce?.
	SWEP.DrawAmmo				= true					-- Should draw the default HL2 ammo counter.
	SWEP.DrawCrosshair			= false					-- Should draw the default crosshair.
	SWEP.DrawWeaponInfoBox		= false					-- Should draw the weapon info box.
	SWEP.PrintName				= "Base BELmod SWEP"	-- 'Nice' Weapon name (Shown on HUD).
	SWEP.Slot					= 2						-- Slot in the weapon selection menu.
	SWEP.SlotPos				= 1						-- Position in the slot.
	SWEP.SwayScale				= 1.0					-- The scale of the viewmodel sway (1.0 should be the default).
	SWEP.WepSelectIcon			= surface.GetTextureID(	-- Path to an texture. Override this in your SWEP to set the icon in the weapon selection.
									"VGUI/gfx/VGUI/=deserteagle=" )
	SWEP.CSMuzzleFlashes		= true					-- Should use Counter-Strike muzzle flashes upon firing

end

/* Easy access */
local ScriptedWeapon			= SWEP

/* Shared config				*/
/* ---------------------------- */
SWEP.AdminSpawnable				= false					-- If false, admins can't spawn that weapon (you can set to false for base weapons).
SWEP.Author						= "McFly"				-- The Author of the SWEP.
SWEP.Category					= "Behind Enemy Lines"	-- The category containing that Weapon. The SWEP menu sorts all the weapons of the same category together. You can create your own.
SWEP.Contact					= ""					-- An e-mail address to contact the author.
SWEP.Folder						= ""					-- The folder in which the SWEP files are located.
SWEP.HoldType					= "pistol"				-- How the weapon is held. (pistol, smg, grenade, ar2, etc...)
SWEP.Instructions				= "Shoot to kill"		-- Short manual of how to use the weapon.
SWEP.m_WeaponDeploySpeed		= 1.5					-- Multiplier of deploy speed.
SWEP.Purpose					= "Kill enemies"		-- What the weapon is made for.
SWEP.Spawnable					= false					-- If false, players can't spawn that weapon (you can set to false for base weapons).
SWEP.ViewModel					=						-- Path to the view model (the weapon viewed from the player's point of view).
									"models/weapons/v_swep_magnum.mdl"
SWEP.ViewModelFlip				= false					-- Should the view model be flipped? (left handed weapon).
SWEP.ViewModelFOV				= 70					-- An angle of FOV used for the view model.
SWEP.WorldModel					= 						-- Path to the world model (the weapon viewed on the ground or in hands of NPCs).
									"models/weapons/w_swep_magnum.mdl"

/* Primary fire configuration	*/
/* ---------------------------- */
SWEP.Primary.Ammo				= "smg1"				-- Ammo type for the primary fire mode ("Pistol", "SMG" etc)
SWEP.Primary.Automatic			= false					-- Should the weapon keep firing if the player's mouse is still down?
SWEP.Primary.ClipSize			= 7						-- The size of a clip (how much you can shoot before you reload)
SWEP.Primary.DefaultClip		= 21					-- The default amount of ammo to give when you get the weapon

/* Secondary fire configuration	*/
/* ---------------------------- */
SWEP.Secondary.Ammo				= "none"				-- Ammo type for the secondary fire mode ("Pistol", "SMG" etc)
SWEP.Secondary.Automatic		= false					-- Should the weapon keep firing if the player's mouse is still down?
SWEP.Secondary.ClipSize			= -1					-- The size of a clip (how much you can shoot before you reload)
SWEP.Secondary.DefaultClip		= -1					-- The default amount of ammo to give when you get the weapon

/* Custom configuration			*/
/* ---------------------------- */
SWEP.MuzzleEffect				= "rg_muzzle_pistol"	-- The effect to use when you shoot
SWEP.Primary.Sound				= "weapons/desert1.wav"	-- The sound it makes when you shoot.
SWEP.Secondary.Sound			= ""					-- The sound it makes when you shoot.
SWEP.Primary.EmptySound			= 						-- The sound it makes when you shoot and clip is empty.
									"weapons/ar2/ar2_empty.wav"
SWEP.Secondary.EmptySound		= ""					-- The sound it makes when you shoot and clip is empty.
SWEP.DeploySound				= 						-- The sound it makes when it is deployed
									"weapons/=deagle=/de_deploy.wav"
SWEP.ClipOutSound				= 						-- The sound it makes when the clip is removed
									"weapons/=deagle=/de_clipout.wav"
SWEP.ClipInSound				= 						-- The sound it makes when the clip is inserted
									"weapons/=deagle=/de_clipin.wav"
SWEP.SlideBackSound				= 						-- The sound it makes when the slide is pulled back
									"weapons/=deagle=/de_slideback.wav"
SWEP.ClipOutTime				= 0.2					-- Time at which clip is removed
SWEP.ClipInTime					= 1.15					-- Time at which clip is inserted
SWEP.SlideBackTime				= 1.8					-- Time at which slide is pulled back
SWEP.ReloadTime					= 2						-- Reload duration

/* Iron sights					*/
/* ---------------------------- */
SWEP.IronSights					= {}
SWEP.IronSights.Enabled			= true					-- Whether the weapon allows iron sights or not.
SWEP.IronSights.FOV				= 55					-- FOV change when using iron sights.
SWEP.IronSights.Position		= 						-- The position offset for the iron sights.
									Vector( -2.161, -3.77, 0.4 )
SWEP.IronSights.Angles			= 						-- The angle offset for the iron sights.
									Vector( 2.295, 0, 3.443 )
SWEP.IronSights.Time			= 0.2					-- How long it takes in seconds to turn iron sights on / off.
SWEP.IronSights.SoundIn			= 						-- Sound played when turned on
									"ambient/materials/rock4.wav"
SWEP.IronSights.SoundOut		= 						-- Sound played when turned off
									"ambient/materials/rock4.wav"
									
/* Holster						*/
/* ---------------------------- */
SWEP.HolsterInfo				= {}
SWEP.HolsterInfo.Enabled		= true					-- Is holster enabled ?
SWEP.HolsterInfo.FOV			= 0						-- FOV change when holstered.
SWEP.HolsterInfo.Position		= Vector( 0, -2, 2 )	-- The position offset when holstered.									
SWEP.HolsterInfo.Angles			= Vector( -20, 25, 0 )	-- The angle offset when holstered.									
SWEP.HolsterInfo.Time			= 0.3					-- How long it takes in seconds to turn holster on / off.
SWEP.HolsterInfo.SoundIn		= 						-- Sound played when turned on
									"ambient/materials/rock4.wav"
SWEP.HolsterInfo.SoundOut		= 						-- Sound played when turned off
									"ambient/materials/rock4.wav"
									
/* When running					*/
/* ---------------------------- */
SWEP.RunInfo					= {}
SWEP.RunInfo.Enabled			= true					-- Is player running ? ?
SWEP.RunInfo.FOV				= 0						-- FOV change when running.
SWEP.RunInfo.Position			= Vector( 1, -8, -5 )	-- The position offset when running.									
SWEP.RunInfo.Angles				= Vector( 55, 0, 0 )	-- The angle offset when running.									
SWEP.RunInfo.Time				= 0.3					-- How long it takes in seconds to turn running on / off.
SWEP.RunInfo.SoundIn			= 						-- Sound played when turned on
									"ambient/materials/rock4.wav"
SWEP.RunInfo.SoundOut			= 						-- Sound played when turned off
									"ambient/materials/rock4.wav"
									
/* When a wall is close			*/
/* ---------------------------- */
SWEP.WallInfo					= {}
SWEP.WallInfo.MinPosition		= Vector( 0, -2, 2 )	-- Position when holstered against a wall.
SWEP.WallInfo.MinAngles			= Vector( -20, 25, 0 )	-- Angles when holstered against a wall.
SWEP.WallInfo.MaxPosition		= Vector( 1, -8, -5 )	-- Default position against a wall.
SWEP.WallInfo.MaxAngles			= Vector( 65, 0, 0 )	-- Default anglase against a wall.
SWEP.WallInfo.StartDistance		= 75					-- Distance from a wall that checks start.

/* Fire modes					*/
/* ---------------------------- */
SWEP.FireMode					= 1						-- Current fire mode
SWEP.FireModes					= {}					-- All fire modes
SWEP.FireModes[1]				= {}					-- This fire mode is a sample single shot mode
SWEP.FireModes[1].Enabled		= true
SWEP.FireModes[1].PrintName		= "Single"
SWEP.FireModes[1].PrintColor	= Color( 25, 225, 100, 255 )
SWEP.FireModes[1].Auto			= false
SWEP.FireModes[1].AutoReload	= false
SWEP.FireModes[1].AmmoTexture	= "VGUI/hud/Bullet44"
SWEP.FireModes[1].ShootDelay	= 0.25
SWEP.FireModes[1].Burst			= 1
SWEP.FireModes[1].BurstDelay	= 0.25
SWEP.FireModes[1].Recoil		= { Up = 3, Down = 1, Left = 2, Right = 2 }
SWEP.FireModes[1].Precision		= 0.98
SWEP.FireModes[1].Spread		= 0.01
SWEP.FireModes[1].Damage		= 60
SWEP.FireModes[1].Round			= "amtp_11x44_430"
SWEP.FireModes[2]				= {}					-- This fire mode is a sample 3 shot burst mode
SWEP.FireModes[2].Enabled		= true
SWEP.FireModes[2].PrintName		= "Burst"
SWEP.FireModes[2].PrintColor	= Color( 225, 225, 75, 255 )
SWEP.FireModes[2].Auto			= false
SWEP.FireModes[2].AutoReload	= true
SWEP.FireModes[2].AmmoTexture	= "VGUI/hud/Bullet44"
SWEP.FireModes[2].ShootDelay	= 0.5
SWEP.FireModes[2].Burst			= 3
SWEP.FireModes[2].BurstDelay	= 0.15
SWEP.FireModes[2].Recoil		= { Up = 5, Down = 2, Left = 3, Right = 3 }
SWEP.FireModes[2].Precision		= 0.8
SWEP.FireModes[2].Spread		= 0.05
SWEP.FireModes[2].Damage		= 50
SWEP.FireModes[2].Round			= "amtp_11x44_430"
SWEP.FireModes[3]				= {}					-- This fire mode is a sample automatic mode
SWEP.FireModes[3].Enabled		= true
SWEP.FireModes[3].PrintName		= "Auto"
SWEP.FireModes[3].PrintColor	= Color( 225, 25, 25, 255 )
SWEP.FireModes[3].Auto			= true
SWEP.FireModes[3].AutoReload	= false
SWEP.FireModes[3].AmmoTexture	= "VGUI/hud/Bullet44"
SWEP.FireModes[3].ShootDelay	= 0.15
SWEP.FireModes[3].Burst			= 1
SWEP.FireModes[3].BurstDelay	= 0.15
SWEP.FireModes[3].Recoil		= { Up = 5, Down = 2, Left = 3, Right = 3 }
SWEP.FireModes[3].Precision		= 0.7
SWEP.FireModes[3].Spread		= 0.05
SWEP.FireModes[3].Damage		= 45
SWEP.FireModes[3].Round			= "amtp_11x44_430"

/************************************************************************************************************************/
/**	NETWORKED VARS																										*/
/************************************************************************************************************************/

/* Set fire mode for client and server */
function SWEP:SetNWFireMode( mode )
	if self.FireModes[mode].Enabled then
		self.Weapon:SetNetworkedInt( "FireMode", mode )
	else
		self:SetNWFireMode( mode % ( table.Count( self.FireModes ) - 1 ) + 1 )
	end
end

/* Get fire mode from client or server */
function SWEP:GetNWFireMode()
	local val = self.Weapon:GetNWInt( "FireMode" )
	if val and val > 0 then return val
	else return 1 end
end

/************************************************************************************************************************/
/**	FUNCTIONS																											*/
/************************************************************************************************************************/

/* Precache resources */
function SWEP:Precache()

	/* Sounds */
	if self.Primary.Sound then util.PrecacheSound( self.Primary.Sound ) end
	if self.Secondary.Sound then util.PrecacheSound( self.Secondary.Sound ) end
	if self.Primary.EmptySound then util.PrecacheSound( self.Primary.EmptySound ) end
	if self.Secondary.EmptySound then util.PrecacheSound( self.Secondary.EmptySound ) end
	if self.DeploySound then util.PrecacheSound( self.DeploySound ) end
	if self.ClipOutSound then util.PrecacheSound( self.ClipOutSound ) end
	if self.ClipInSound then util.PrecacheSound( self.ClipInSound ) end
	if self.SlideBackSound then util.PrecacheSound( self.SlideBackSound ) end
	if self.IronSights.SoundIn then util.PrecacheSound( self.IronSights.SoundIn ) end
	if self.IronSights.SoundOut then util.PrecacheSound( self.IronSights.SoundOut ) end
	if self.RunInfo.SoundIn then util.PrecacheSound( self.RunInfo.SoundIn ) end
	if self.RunInfo.SoundOut then util.PrecacheSound( self.RunInfo.SoundOut ) end
	if self.HolsterInfo.SoundIn then util.PrecacheSound( self.HolsterInfo.SoundIn ) end
	if self.HolsterInfo.SoundOut then util.PrecacheSound( self.HolsterInfo.SoundOut ) end
end

/* Initialization */
function SWEP:Initialize()

	/* NPC config */
	if SERVER then
        self:SetNPCMinBurst( 3 )
        self:SetNPCMaxBurst( 30 )
        self:SetNPCFireRate( 0.07 )
    end
end

/* Primary attack */
function SWEP:PrimaryAttack()

	/* Switch fire mode */
	if self.Owner:KeyDown( IN_USE ) then
	
		/* Not too often */
		if self.SwitchModeTime and self.SwitchModeTime > CurTime() then return end
		self.SwitchModeTime = CurTime() + 0.25
	
		/* Change fire mode, play sound & set to auto if needed */
		self:SetNWFireMode( self:GetNWFireMode() % ( table.Count( self.FireModes ) - 1 ) + 1 )
		self.Weapon:EmitSound( self.Primary.EmptySound )
		self.Primary.Automatic = self:GetFireMode().Auto
		return
	end
	
	/* Play sound if empty */
	if self.Weapon:Clip1() == 0 then
		
		/* Not too often */
		if self.EmptyShotTime and self.EmptyShotTime > CurTime() then return end
		self.EmptyShotTime = CurTime() + self:GetFireMode().ShootDelay
		
		/* Play sound */
		self.Weapon:EmitSound( self.Primary.EmptySound )
	end

	/* Do nothing if we cannot use primary attack */
	if self:CanPrimaryAttack() then
	
		/* Deal with burst */
		for i = 1,self:GetFireMode().Burst do
		
			/* Apply burst delay between shots */
			timer.Simple( self:GetFireMode().BurstDelay * ( i - 1 ), function()
				
				/* Break if the weapon is no longer valid (player died or something) */
				if not IsValid( self.Weapon ) or not IsValid( self.Owner ) then return end
				
				/* Break if the clip is empty */
				if self.Weapon:Clip1() == 0 then return end
	
				/* Weapon */
				self.Weapon:EmitSound( self.Primary.Sound )
				self.Weapon:TakePrimaryAmmo( 1 )
				self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
				self.Weapon:SetNextPrimaryFire( CurTime() + self:GetFireMode().ShootDelay )
				
				/* Owner */
				self.Owner:SetAnimation( PLAYER_ATTACK1 )
				self.Owner:MuzzleFlash()
				
				/* Effects */
				if self.MuzzleEffect then
					local fx = EffectData()
					fx:SetEntity( self.Weapon )
					fx:SetOrigin( self.Owner:GetShootPos() )
					fx:SetNormal( self.Owner:GetAimVector() )
					fx:SetAttachment( "1" )
					util.Effect( self.MuzzleEffect, fx )
				end
				
				/* Shoot a bullet */
				self:ShootBullet( self:GetFireMode().Damage, self:GetFireMode().Burst, self:GetFireMode().Spread )
				
				/* Apply recoil */
				self:DoRecoil()
				
				/* Check if clip is empty */
				self:CheckClipEmpty()
			end)
		end
	end
end

/* Secondary attack */
function SWEP:SecondaryAttack()
	return false
end

/* Deploy */
function SWEP:Deploy()
	self.Weapon:SendWeaponAnim( ACT_VM_DRAW )
	timer.Simple( 0.01, function()
		if not IsValid( self.Weapon ) then return false end
        self.Weapon:EmitSound( self.DeploySound )
	end)
	return true
end

/* Reload */
function SWEP:Reload()
	
	/* Do nothing if we still have some ammo in the clip */
	if self.Weapon:Clip1() >= self.Primary.ClipSize then return end
	
	/* Default behaviour */
	self.Weapon:DefaultReload( ACT_VM_RELOAD )
	
	/* Helpers */
	self.Reloading = true
	timer.Simple( 2, function()
		self.Reloading = false
	end)
	
	/* Play sounds */
	timer.Simple( 0.2, function()
		if not IsValid( self.Weapon ) then return end
		self.Weapon:EmitSound( self.ClipOutSound )
    end)
    timer.Simple( 1.15, function()
		if not IsValid( self.Weapon ) then return end
		self.Weapon:EmitSound( self.ClipInSound )
    end)
    timer.Simple( 1.8, function()
		if not IsValid( self.Weapon ) then return end
        self.Weapon:EmitSound( self.SlideBackSound )
    end)
end

/* Allow / disallow primary attack */
function SWEP:CanPrimaryAttack()
	return
		self.Weapon:Clip1() > 0 and
		( not self.Owner:KeyDown( IN_SPEED ) or self.Owner:GetVelocity() == Vector( 0, 0, 0 ) ) and
		not self.Owner:KeyDown( IN_USE ) and
		not self.HolsterInfo.Active and
		not self.RunInfo.Active and
		not self:CheckHitsWall().Hit
end

/* Holster enabled ? */
function SWEP:Holster()
	/* Return */
	return self.HolsterInfo.Enabled
end

/* Shoot bullet */
function SWEP:ShootBullet( dmg, cnt, loose )

	/* Ensure proper values */
	dmg					= dmg or 0
	cnt					= cnt or 1
	loose				= self.loose or 0.01
	
	/* Variables */
	local prec			= math.Clamp( self:GetFireMode().Precision, 0, 1 )
	local spread		= Vector( 1 - prec, 1 - prec, 0 )
	local aim			= self.Owner:GetAimVector()
	local dir			= aim
	local src			= self.Owner:GetShootPos()
	local ammo			= self.Primary.Ammo
	
	/* Calculate final spread */
	if not self.IronSights then
		spread			= spread + VectorRand() * loose * Vector( 1, 1, 0)
		dir				= dir + VectorRand() * loose
	end
	
	/* Create a bullet */
	if not self:GetFireMode().Round or self:GetFireMode().Round == "default" then
		local bullet		= {}
		bullet.Num			= cnt
		bullet.Src			= src
		bullet.Dir			= dir
		bullet.Spread		= spread
		bullet.Tracer		= 1
		bullet.TracerName	= "Tracer"
		bullet.Force		= 1
		bullet.Damage		= 0
		bullet.AmmoType		= ammo
		
		/* Shoot it */
		self.Owner:FireBullets( bullet )
	end
	
	/* Shoot bullet entities */
	if SERVER and self:GetFireMode().Round != "default" then
			
		/* Create the entity */
		local bulletEnt	= ents.Create( self:GetFireMode().Round )
		if not IsValid( bulletEnt ) then return end
		
		/* Configure it */
		bulletEnt:SetAngles( dir:Angle() + Angle( 90, 0, 0 ) )
		bulletEnt:SetPos( src + aim * 50 )
		bulletEnt:SetOwner( self.Owner )
		bulletEnt:Spawn()
		bulletEnt:Activate()
	end
end

/* Calculate the recoil */
function SWEP:CalculateRecoil()

	/* Variables */
	local vRecoil		= {
		[0] = -self:GetFireMode().Recoil.Down,
		[1] = self:GetFireMode().Recoil.Up,
	}
	local hRecoil		= {
		[0] = -self:GetFireMode().Recoil.Left,
		[1] = self:GetFireMode().Recoil.Right
	}
	
	/* Calculate the angles */
	local recoil			= Angle( 
		table.Random( vRecoil ) * math.Rand( vRecoil[0], vRecoil[1] ),
		table.Random( hRecoil ) * math.Rand( hRecoil[0], hRecoil[1] ),
		0 )
		
	/* Return it*/
	return recoil
end

/* Iron sights */
function SWEP:DoIronSights()

	/* If we don't want to use iron sights, skip this */
	if not self.IronSights or not self.IronSights.Enabled then return end
	
	/* We cannot use iron sights with action key down or when running or when reloading */
	if self.Owner:KeyDown( IN_USE ) or self.RunInfo.Active or self.Reloading then
		if self.IronSights.Active then
			self:SetIronSights( false )
		end
		return
	end
	
	/* Can't use iron sights if weapon is holstered */
	if self.HolsterInfo.Active then
		if self.IronSights.Active then
			self:SetIronSights( false )
		end
		return
	end

	/* Secondary fire pressed = activate */
	if self.Owner:KeyPressed( IN_ATTACK2 ) then
		if not self.IronSights.Active then
			self:SetIronSights( true )
		end
	end
	
	/* Secondary fire released = deactivate */
	if self.Owner:KeyReleased( IN_ATTACK2 ) then
		if self.IronSights.Active then
			self:SetIronSights( false )
		end
	end
end

/* Iron sights */
function SWEP:DoRunning()

	/* If we don't want to use running info, skip this */
	if not self.RunInfo or not self.RunInfo.Enabled then return end
	
	/* Do not apply if we're reloading */
	if self.Reloading then
		if self.RunInfo.Active then
			self:SetRunning( false )
		end
		return
	end

	/* Player is running */
	if self.Owner:KeyDown( IN_SPEED ) and self.Owner:GetVelocity() != Vector( 0, 0, 0 ) then
		if not self.RunInfo.Active then
			self:SetRunning( true )
		end
	
	/* Player is not running */
	elseif not self.Owner:KeyDown( IN_SPEED ) or self.Owner:GetVelocity() == Vector( 0, 0, 0 ) then
		if self.RunInfo.Active then
			self:SetRunning( false )
		end
	end
end

/* Holster */
function SWEP:DoHolster()

	/* If we do not want holster, skip this */
	if not self.HolsterInfo or not self.HolsterInfo.Enabled then return end
	
	/* Un-holster if we attack and are allowed to */
	if self.Owner:KeyDown( IN_ATTACK ) and self:CanPrimaryAttack() then
		if self.HolsterInfo.Active then
			self:SetHolster( false )
		end
		return
	end
	
	/* Un-holster if using iron sights or running or reloading */
	if self.IronSights.Active or self.RunInfo.Active or self.Reloading then
		if self.HolsterInfo.Active then
			self:SetHolster( false )
		end
		return
	end
	
	/* Check if time is ok */
	if self.HolsterInfo.NextUse and CurTime() < self.HolsterInfo.NextUse then return end
		
	/* Toggle */
	if self.Owner:KeyDown( IN_USE ) and self.Owner:KeyPressed( IN_ATTACK2 ) then
	
		/* Next holster time */
		self.HolsterInfo.NextUse = CurTime() + self.HolsterInfo.Time * 2
	
		/* Variables */
		local active	= false
		
		/* Get info */
		if not self.HolsterInfo.Active then
			active	= true
		end
		
		/* Toggle holster */
		if self.HolsterInfo.Active != active then
			self:SetHolster( active )
		end
	end
end

/* Activate / deactivate iron sights */
function SWEP:SetIronSights( val )

	/* Activate */
	if val then
	
		/* Change FOV */
		self.Owner:SetFOV( self.IronSights.FOV, self.IronSights.Time )
		
		/* Stop sound */
		if self.IronSights.SoundOut then
			self.Weapon:StopSound( self.IronSights.SoundOut )
		end
		
		/* Play sound */
		if self.IronSights.SoundIn then
			self.Weapon:EmitSound( self.IronSights.SoundIn )
		end
	
	/* Deactivate */
	else
	
		/* Reset FOV */
		self.Owner:SetFOV( 0, self.IronSights.Time )
		
		/* Stop sound */
		if self.IronSights.SoundIn then
			self.Weapon:StopSound( self.IronSights.SoundIn )
		end
		
		/* Play sound */
		if self.IronSights.SoundOut then
			self.Weapon:EmitSound( self.IronSights.SoundOut )
		end
	
	end
	
	/* Update */
	self.IronSights.Active	= val

	/* Send user message */
	if SERVER then
		umsg.Start( "UMSG_IronSights", self.Owner )
		umsg.Bool( tobool( val ) )
		umsg.End()
	end
end

/* Activate / deactivate running things */
function SWEP:SetRunning( val )

	/* Activate */
	if val then
	
		/* Change FOV */
		self.Owner:SetFOV( self.RunInfo.FOV, self.RunInfo.Time )
		
		/* Play sound */
		if self.RunInfo.SoundIn then
			self.Weapon:EmitSound( self.RunInfo.SoundIn )
		end
	
	/* Deactivate */
	else
	
		/* Reset FOV */
		self.Owner:SetFOV( 0, self.RunInfo.Time )
		
		/* Play sound */
		if self.RunInfo.SoundOut then
			self.Weapon:EmitSound( self.RunInfo.SoundOut )
		end
	
	end
	
	/* Update */
	self.RunInfo.Active	= val

	/* Send user message */
	if SERVER then
		umsg.Start( "UMSG_Running", self.Owner )
		umsg.Bool( tobool( val ) )
		umsg.End()
	end
end

/* Activate / deactivate holster */
function SWEP:SetHolster( val )

	/* Variables */
	local fov		= 0
	
	/* Get info */
	if not self.HolsterInfo.Active then
		fov			= self.HolsterInfo.FOV
	end

	/* Update things */
	self.Owner:SetFOV( fov, self.HolsterInfo.Time )
	self.HolsterInfo.Active	= val
	
	/* Sound */
	if val and self.HolsterInfo.SoundIn then self.Weapon:EmitSound( self.HolsterInfo.SoundIn )
	elseif not val and self.HolsterInfo.SoundOut then self.Weapon:EmitSound( self.HolsterInfo.SoundOut ) end

	/* Send user message */
	if SERVER then
		umsg.Start( "UMSG_Holster", self.Owner )
		umsg.Bool( tobool( val ) )
		umsg.End()
	end
end

/* Every frame */
function SWEP:Think()
	
	/* Check for iron sights */
	self:DoIronSights()
	
	/* Check for holster */
	self:DoHolster()
	
	/* Check for player running */
	self:DoRunning()
end

/* Check if it hits a wall */
function SWEP:CheckHitsWall()

	/* Variables */
	local ply			= self.Owner
	local wpn			= self.Weapon
	local start			= self.Owner:GetShootPos()
	local aim			= self.Owner:GetAimVector()
	local len			= self.WallInfo.StartDistance
	
	/* Create a trace from the weapon */
	local traceData		= {}
	traceData.start		= start
	traceData.endpos	= start + aim * len
	traceData.filter	= { [1] = ply, [2] = wpn }
	traceData.mask		= MASK_SOLID_BRUSHONLY
	local trace			= util.TraceLine( traceData )
	
	/* Return the trace info */
	return trace
end

/* Checks if clip is empty and reloads / plays sound */
function SWEP:CheckClipEmpty()

	/* Delay action to let last shot end */
	timer.Simple( self:GetFireMode().ShootDelay * 2, function()
	
		/* Auto-reload if empty and enabled */
		if IsValid( self.Weapon ) and self.Weapon:Clip1() == 0 then
			
			/* Reload if auto-reload is enabled */
			if self:GetFireMode().AutoReload and not self.Reloading then self:Reload() end
		end
	end)
	
	/* Return value */
	return self.Weapon:Clip1() == 0
end

/* Get the current fire mode */
function SWEP:GetFireMode()
	return self.FireModes[ self:GetNWFireMode() ]
end

/* Server only functions */
if SERVER then

/* Apply recoil */
function SWEP:DoRecoil()

	/* Calculate the angles */
	local recoil			= self:CalculateRecoil()
	local view				= self.Owner:EyeAngles() - recoil
		
	/* Punch view */
	self.Owner:ViewPunch( recoil )
	
	/* Update view angles */
	self.Owner:SetEyeAngles( view )
end

end					-- SERVER

/* Client only functions */
if CLIENT then

/* HUD */
function SWEP:DrawHUD()
	
	/* Prepare surface */
	local texture = surface.GetTextureID( self:GetFireMode().AmmoTexture )
	surface.SetTexture( texture )
	surface.SetDrawColor( 255, 255, 255, 255 )
	
	/* Draw as many bullets as we have */
	for i = 1,self.Weapon:Clip1() do
		surface.DrawTexturedRectRotated(
			ScrW() - ( ( ScrW() / 1920 ) * 100 ),
			ScrH() - ( i * ( ( ScrH() / 1080 ) * 40 ) ),
			ScrW() / 1920 * 32,
			ScrH() / 1080 * 96,
			90 )
	end
	
	/* Text sizes */
	surface.SetFont( "DefaultBold" )
	local w1,h1	= surface.GetTextSize( "Fire mode:  " )
	local w2,h2	= surface.GetTextSize( self:GetFireMode().PrintName )
	local x1	= ScrW() - ScrW() / 1920 * 200 - w1 - w2
	local y1	= ScrH() - ScrH() / 1080 * 45 - math.max( h1, h2 )
	local x2	= x1 + w1
	local y2	= y1
	
	/* Draw fire mode outline */
	surface.SetDrawColor( self:GetFireMode().PrintColor )
	surface.DrawOutlinedRect(
		x1 - 3,
		y1 - 3,
		w1 + w2 + 6,
		math.max( h1, h2 ) + 6 )
	
	/* Draw fire mode text part 1 */
	local txtStruc1 = {}
	txtStruc1["pos"] = { x1, y1 }
	txtStruc1["color"] = Color( 150, 150, 150, 255 )
	txtStruc1["text"] = "Fire mode:"
	txtStruc1["font"] = "DefaultBold"
	txtStruc1["xalign"] = TEXT_ALIGN_LEFT
	txtStruc1["yalign"] = TEXT_ALIGN_TOP
	draw.TextShadow( txtStruc1, 1, 200 )
	
	/* Draw fire mode text part 2 */
	local txtStruc2 = {}
	txtStruc2["pos"] = { x2, y2 }
	txtStruc2["color"] = self:GetFireMode().PrintColor
	txtStruc2["text"] = self:GetFireMode().PrintName
	txtStruc2["font"] = "DefaultBold"
	txtStruc2["xalign"] = TEXT_ALIGN_LEFT
	txtStruc2["yalign"] = TEXT_ALIGN_TOP
	draw.TextShadow( txtStruc2, 1, 200 )
end

/* Do not display default clip and ammo */
function SWEP:CustomAmmoDisplay()
	self.AmmoDisplay = self.AmmoDisplay or {}
	self.AmmoDisplay.Draw = false	
	return self.AmmoDisplay
end

/* Update model view position and angle */
function SWEP:GetViewModelPosition( pos, ang )

	/* Open configuration menu if requested */
	if self.Owner:KeyDown( IN_USE ) and self.Owner:KeyPressed( IN_RELOAD ) then
		if not Swepper:IsOpen() then
			Swepper:Open( self )
		end
	end
	
	/* Show crosshair if configurator is open */
	self.DrawCrosshair					= Swepper:IsOpen()

	/* Init last frame time if needed */
	if not self.LastFrameTime then self.LastFrameTime = CurTime() end
	
	/* Time elapsed since last frame */
	local timeElapsed = CurTime() - self.LastFrameTime
	
	/* Calculate pos and ang for Iron Sights */
	pos, ang = self:CalculateIronSights( timeElapsed, pos, ang )
	
	/* Calculate pos and ang for Running */
	pos, ang = self:CalculateRunning( timeElapsed, pos, ang )
	
	/* Calculate pos and ang for Holster */
	pos, ang = self:CalculateHolster( timeElapsed, pos, ang )
	
	/* Calculate pos and ang for close walls */
	pos, ang = self:CalculateWalls( pos, ang )
	
	/* Update last frame time */
	self.LastFrameTime = CurTime()
	
	/* Return new values */
	return pos, ang
end

/* Calculate pos and ang for Iron Sights */
function SWEP:CalculateIronSights( timeElapsed, pos, ang )

	/* If iron sights are disabled, return default */
	if not self.IronSights or not self.IronSights.Enabled then return pos, ang end
	
	/* Update values if the configurator is open */
	if Swepper:IsOpen() and Swepper.IsIronSightsActive() then
		self.IronSights.Position.x		= GetConVarNumber( "is_pos_x" )
		self.IronSights.Position.y		= GetConVarNumber( "is_pos_y" )
		self.IronSights.Position.z		= GetConVarNumber( "is_pos_z" )
		self.IronSights.Angles.x		= GetConVarNumber( "is_ang_p" )
		self.IronSights.Angles.y		= GetConVarNumber( "is_ang_y" )
		self.IronSights.Angles.z		= GetConVarNumber( "is_ang_r" )
	end
	
	/* Iron sights are active */
	if self.IronSights.Active or ( Swepper:IsOpen() and Swepper:IsIronSightsActive() ) then
	
		/* If the elapsed time hasn't been created yet, do it */
		self.IronSights.Elapsed = self.IronSights.Elapsed or 0
		
		/* Update elapsed */
		self.IronSights.Elapsed = math.Clamp( self.IronSights.Elapsed + timeElapsed, 0, self.IronSights.Time )
		
	/* Iron sights are inactive */
	else
	
		/* If the elapsed time hasn't been created yet, do it */
		self.IronSights.Elapsed = self.IronSights.Elapsed or self.IronSights.Time
		
		/* Update elapsed */
		self.IronSights.Elapsed = math.Clamp( self.IronSights.Elapsed - timeElapsed, 0, self.IronSights.Time )
		
	end
	
	/* Calculate multiplier (ratio: 0 <= mul <= 1) */
	local mul = self.IronSights.Elapsed / self.IronSights.Time
	
	/* Calculate angles */
	ang:RotateAroundAxis( ang:Right(), self.IronSights.Angles.x * mul )
	ang:RotateAroundAxis( ang:Up(), self.IronSights.Angles.y * mul )
	ang:RotateAroundAxis( ang:Forward(), self.IronSights.Angles.z * mul )
	
	/* Calculate position */
	local offset	= self.IronSights.Position
	pos = pos + offset.x * ang:Right() * mul
	pos = pos + offset.y * ang:Forward() * mul
	pos = pos + offset.z * ang:Up() * mul
	
	/* Return new values */
	return pos, ang
end

/* Calculate pos and ang for Running */
function SWEP:CalculateRunning( timeElapsed, pos, ang )

	/* If running is disabled, return default */
	if not self.RunInfo or not self.RunInfo.Enabled then return pos, ang end
	
	/* Update values if the configurator is open */
	if Swepper:IsOpen() and Swepper:IsRunningActive() then
		self.RunInfo.Position.x		= GetConVarNumber( "run_pos_x" )
		self.RunInfo.Position.y		= GetConVarNumber( "run_pos_y" )
		self.RunInfo.Position.z		= GetConVarNumber( "run_pos_z" )
		self.RunInfo.Angles.x		= GetConVarNumber( "run_ang_p" )
		self.RunInfo.Angles.y		= GetConVarNumber( "run_ang_y" )
		self.RunInfo.Angles.z		= GetConVarNumber( "run_ang_r" )
	end
	
	/* Running is active */
	if self.RunInfo.Active or ( Swepper:IsOpen() and Swepper:IsRunningActive() ) then
	
		/* If the elapsed time hasn't been created yet, do it */
		self.RunInfo.Elapsed = self.RunInfo.Elapsed or 0
		
		/* Update elapsed */
		self.RunInfo.Elapsed = math.Clamp( self.RunInfo.Elapsed + timeElapsed, 0, self.RunInfo.Time )
		
	/* Running is inactive */
	else
	
		/* If the elapsed time hasn't been created yet, do it */
		self.RunInfo.Elapsed = self.RunInfo.Elapsed or self.RunInfo.Time
		
		/* Update elapsed */
		self.RunInfo.Elapsed = math.Clamp( self.RunInfo.Elapsed - timeElapsed, 0, self.RunInfo.Time )
		
	end
	
	/* Calculate multiplier (ratio: 0 <= mul <= 1) */
	local mul = self.RunInfo.Elapsed / self.RunInfo.Time
	
	/* Calculate angles */
	ang:RotateAroundAxis( ang:Right(), self.RunInfo.Angles.x * mul )
	ang:RotateAroundAxis( ang:Up(), self.RunInfo.Angles.y * mul )
	ang:RotateAroundAxis( ang:Forward(), self.RunInfo.Angles.z * mul )
	
	/* Calculate position */
	local offset	= self.RunInfo.Position
	pos = pos + offset.x * ang:Right() * mul
	pos = pos + offset.y * ang:Forward() * mul
	pos = pos + offset.z * ang:Up() * mul
	
	/* Return new values */
	return pos, ang
end

/* Calculate pos and ang for Holster */
function SWEP:CalculateHolster( timeElapsed, pos, ang )

	/* If holster is disabled, return default */
	if not self.HolsterInfo or not self.HolsterInfo.Enabled then return pos, ang end
	
	/* Update values if the configurator is open */
	if Swepper:IsOpen() and Swepper.IsHolsterActive() then
		self.HolsterInfo.Position.x		= GetConVarNumber( "hol_pos_x" )
		self.HolsterInfo.Position.y		= GetConVarNumber( "hol_pos_y" )
		self.HolsterInfo.Position.z		= GetConVarNumber( "hol_pos_z" )
		self.HolsterInfo.Angles.x		= GetConVarNumber( "hol_ang_p" )
		self.HolsterInfo.Angles.y		= GetConVarNumber( "hol_ang_y" )
		self.HolsterInfo.Angles.z		= GetConVarNumber( "hol_ang_r" )
	end
	
	/* Holster is active */
	if self.HolsterInfo.Active or ( Swepper:IsOpen() and Swepper:IsHolsterActive() ) then
	
		/* If the elapsed time hasn't been created yet, do it */
		self.HolsterInfo.Elapsed = self.HolsterInfo.Elapsed or 0
		
		/* Update elapsed */
		self.HolsterInfo.Elapsed = math.Clamp( self.HolsterInfo.Elapsed + timeElapsed, 0, self.HolsterInfo.Time )
		
	/* Holster is inactive */
	else
	
		/* If the elapsed time hasn't been created yet, do it */
		self.HolsterInfo.Elapsed = self.HolsterInfo.Elapsed or self.HolsterInfo.Time
		
		/* Update elapsed */
		self.HolsterInfo.Elapsed = math.Clamp( self.HolsterInfo.Elapsed - timeElapsed, 0, self.HolsterInfo.Time )
		
	end
	
	/* Calculate multiplier (ratio: 0 <= mul <= 1) */
	local mul = self.HolsterInfo.Elapsed / self.HolsterInfo.Time
	
	/* Calculate angles */
	ang:RotateAroundAxis( ang:Right(), self.HolsterInfo.Angles.x * mul )
	ang:RotateAroundAxis( ang:Up(), self.HolsterInfo.Angles.y * mul )
	ang:RotateAroundAxis( ang:Forward(), self.HolsterInfo.Angles.z * mul )
	
	/* Calculate position */
	local offset	= self.HolsterInfo.Position
	pos = pos + offset.x * ang:Right() * mul
	pos = pos + offset.y * ang:Forward() * mul
	pos = pos + offset.z * ang:Up() * mul
	
	/* Return new values */
	return pos, ang
end

/* Calculate pos and ang for close walls */
function SWEP:CalculateWalls( pos, ang )

	/* Update values if the configurator is open */
	if Swepper:IsOpen() and Swepper.IsWallActive() then
		if not self.HolsterInfo.Active then
			self.WallInfo.MaxPosition.x		= GetConVarNumber( "wal_pos_x" )
			self.WallInfo.MaxPosition.y		= GetConVarNumber( "wal_pos_y" )
			self.WallInfo.MaxPosition.z		= GetConVarNumber( "wal_pos_z" )
			self.WallInfo.MaxAngles.x		= GetConVarNumber( "wal_ang_p" )
			self.WallInfo.MaxAngles.y		= GetConVarNumber( "wal_ang_y" )
			self.WallInfo.MaxAngles.z		= GetConVarNumber( "wal_ang_r" )
		else
			self.WallInfo.MinPosition.x		= GetConVarNumber( "wal_pos_x" )
			self.WallInfo.MinPosition.y		= GetConVarNumber( "wal_pos_y" )
			self.WallInfo.MinPosition.z		= GetConVarNumber( "wal_pos_z" )
			self.WallInfo.MinAngles.x		= GetConVarNumber( "wal_ang_p" )
			self.WallInfo.MinAngles.y		= GetConVarNumber( "wal_ang_y" )
			self.WallInfo.MinAngles.z		= GetConVarNumber( "wal_ang_r" )
		end
	end
	
	/* Check if the SWEP hits a wall */
	local trace			= self:CheckHitsWall()
	local mul			= 0
	local offsetPos		= self.WallInfo.MaxPosition
	local offsetAng		= self.WallInfo.MaxAngles
	local len			= self.WallInfo.StartDistance
	
	/* Calculate multiplier (ratio: 0 <= mul <= 1) */
	if trace.Hit then
		local trLen			= trace.HitPos - self.Owner:GetShootPos()
		local trSqX			= math.pow( trLen.x, 2 )
		local trSqY			= math.pow( trLen.y, 2 )
		local trSqZ			= math.pow( trLen.z, 2 )
		local length		= math.sqrt( trSqX + trSqY + trSqZ )
		mul					= 1 - ( length / len )
		
	/* Show all possible states if configurator is open */
	elseif Swepper:IsOpen() and Swepper:IsWallActive() then
		mul					= ( math.sin( CurTime() ) + 1 ) / 2
	end
	
	/* Add smoothness */
	self.LastHitMul			= self.LastHitMul or mul
	mul						= self.LastHitMul - ( self.LastHitMul - mul ) * 0.075
	mul						= math.Round( mul, 4 )
	self.LastHitMul			= mul
	
	/* If holstered then use min pos / ang */
	if self.HolsterInfo.Active then
		offsetPos		= self.WallInfo.MinPosition
		offsetAng		= self.WallInfo.MinAngles
	end
	
	/* Calculate angles */
	ang:RotateAroundAxis( ang:Right(), offsetAng.x * mul )
	ang:RotateAroundAxis( ang:Up(), offsetAng.y * mul )
	ang:RotateAroundAxis( ang:Forward(), offsetAng.z * mul )
	
	/* Calculate position */
	pos = pos + offsetPos.x * ang:Right() * mul
	pos = pos + offsetPos.y * ang:Forward() * mul
	pos = pos + offsetPos.z * ang:Up() * mul
	
	/* Return new values */
	return pos, ang
end

end					-- CLIENT

/* User messages */
if CLIENT then

/* Activate / deactivate iron sights */
function SWEP.UMSG_IronSights( msg, self )

	/* Read value */
	local val = msg:ReadBool()
	
	/* Set iron sights */
	self.IronSights.Active = val
end
usermessage.Hook( "UMSG_IronSights", SWEP.UMSG_IronSights, SWEP )

/* Activate / deactivate runniong things */
function SWEP.UMSG_Running( msg, self )

	/* Read value */
	local val = msg:ReadBool()
	
	/* Set iron sights */
	self.RunInfo.Active = val
end
usermessage.Hook( "UMSG_Running", SWEP.UMSG_Running, SWEP )

/* Activate / deactivate holster */
function SWEP.UMSG_Holster( msg, self )

	/* Read value */
	local val = msg:ReadBool()
	
	/* Set iron sights */
	self.HolsterInfo.Active = val
end
usermessage.Hook( "UMSG_Holster", SWEP.UMSG_Holster, SWEP )

end					-- CLIENT